home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / gnu-tar / gnu.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  11KB  |  562 lines

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <ctype.h>
  5.  
  6. #ifdef BSD42
  7. #include <sys/dir.h>
  8. #else
  9. #ifdef MSDOS
  10. #include <sys/dir.h>
  11. #else
  12. #ifdef USG
  13. #ifdef NDIR
  14. #include <ndir.h>
  15. #else
  16. #include <dirent.h>
  17. #endif
  18. #ifndef DIRECT
  19. #define direct dirent
  20. #endif
  21. #define DP_NAMELEN(x) strlen((x)->d_name)
  22. #else
  23. /*
  24.  * FIXME: On other systems there is no standard place for the header file
  25.  * for the portable directory access routines.    Change the #include line
  26.  * below to bring it in from wherever it is.
  27.  */
  28. #include "ndir.h"
  29. #endif
  30. #endif
  31. #endif
  32.  
  33. #ifndef DP_NAMELEN
  34. #define DP_NAMELEN(x)   (x)->d_namlen
  35. #endif
  36.  
  37. #ifdef __STDC__
  38. #define VOIDSTAR void *
  39. #else
  40. #define VOIDSTAR char *
  41. #endif
  42.  
  43. extern VOIDSTAR malloc();
  44.  
  45. #include "tar.h"
  46.  
  47. extern time_t new_time;
  48. extern FILE *msg_file;
  49.  
  50. extern VOIDSTAR init_buffer();
  51. extern char *get_buffer();
  52. extern void add_buffer();
  53. extern void flush_buffer();
  54.  
  55. extern char *new_name();
  56.  
  57. struct stat statbuf;
  58.  
  59. struct dirname {
  60.     struct dirname *next;
  61.     char *name;
  62.     char *dir_text;
  63.     int dev;
  64.     int ino;
  65. };
  66. struct dirname *dir_list;
  67. time_t this_time;
  68.  
  69. void add_dir_name();    /* AMIGA    */
  70.  
  71. void
  72. add_dir(name,dev,ino,text)
  73. char *name;
  74. char *text;
  75. {
  76.     struct dirname *dp;
  77.  
  78.     dp=(struct dirname *)malloc(sizeof(struct dirname));
  79.     if(!dp)
  80.         abort();
  81.     dp->next=dir_list;
  82.     dir_list=dp;
  83.     dp->dev=dev;
  84.     dp->ino=ino;
  85.     dp->name=malloc(strlen(name)+1);
  86.     strcpy(dp->name,name);
  87.     dp->dir_text=text;
  88. }
  89.  
  90. void
  91. read_dir_file(name)
  92. char *name;
  93. {
  94.     int dev;
  95.     int ino;
  96.     char *strp;
  97.     FILE *fp;
  98.     static char buf[512];
  99.  
  100.     time(&this_time);
  101.     fp=fopen(name,"r");
  102.     if(fp==0) {
  103.         msg_perror("Can't open %s",name);
  104.         return;
  105.     }
  106.     fgets(buf,sizeof(buf),fp);
  107.     if(!f_new_files) {
  108.         f_new_files++;
  109.         new_time=atol(buf);
  110.     }
  111.     while(fgets(buf,sizeof(buf),fp)) {
  112.         strp= &buf[strlen(buf)];
  113.         if(strp[-1]=='\n')
  114.             strp[-1]='\0';
  115.         strp=buf;
  116.         dev=atol(strp);
  117.         while(isdigit(*strp))
  118.             strp++;
  119.         ino=atol(strp);
  120.         while(isspace(*strp))
  121.             strp++;
  122.         while(isdigit(*strp))
  123.             strp++;
  124.         strp++;
  125.         add_dir(un_quote_string(strp),dev,ino,(char *)0);
  126.     }
  127.     fclose(fp);
  128. }
  129.  
  130. void
  131. write_dir_file(name)
  132. char *name;
  133. {
  134.     FILE *fp;
  135.     struct dirname *dp;
  136.     char *str;
  137.     extern char *quote_copy_string();
  138.  
  139.     fp=fopen(name,"w");
  140.     if(fp==0) {
  141.         msg_perror("Can't write to %s",name);
  142.         return;
  143.     }
  144.     fprintf(fp,"%lu\n",this_time);
  145.     for(dp=dir_list;dp;dp=dp->next) {
  146.         if(!dp->dir_text)
  147.             continue;
  148.         str=quote_copy_string(dp->name);
  149.         if(str) {
  150.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
  151.             free(str);
  152.         } else
  153.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
  154.     }
  155.     fclose(fp);
  156. }
  157.  
  158. struct dirname *
  159. get_dir(name)
  160. char *name;
  161. {
  162.     struct dirname *dp;
  163.  
  164.     for(dp=dir_list;dp;dp=dp->next) {
  165.         if(!strcmp(dp->name,name))
  166.             return dp;
  167.     }
  168.     return 0;
  169. }
  170.  
  171.  
  172. /* Collect all the names from argv[] (or whatever), then expand them into
  173.    a directory tree, and put all the directories at the beginning. */
  174. collect_and_sort_names()
  175. {
  176.     struct name *n,*n_next;
  177.     int num_names;
  178.     int name_cmp();
  179.     char *merge_sort();
  180.  
  181.     name_gather();
  182.  
  183.     if(gnu_dumpfile)
  184.         read_dir_file(gnu_dumpfile);
  185.     if(!namelist) addname(".");
  186.     for(n=namelist;n;n=n_next) {
  187.         n_next=n->next;
  188.         if(n->found || n->dir_contents)
  189.             continue;
  190.         if(n->regexp)           /* FIXME just skip regexps for now */
  191.             continue;
  192.         if(n->change_dir)
  193.             if(chdir(n->change_dir)<0) {
  194.                 msg_perror("can't chdir to %s",n->change_dir);
  195.                 continue;
  196.             }
  197.  
  198.         if(lstat(n->name,&statbuf)<0) {
  199.             msg_perror("can't stat %s",n->name);
  200.             continue;
  201.         }
  202.         if((statbuf.st_mode&S_IFMT)==S_IFDIR) {
  203.             n->found++;
  204.             add_dir_name(n->name,statbuf.st_dev);
  205.         }
  206.     }
  207.  
  208.     num_names=0;
  209.     for(n=namelist;n;n=n->next)
  210.         num_names++;
  211.     namelist=(struct name *)merge_sort((VOIDSTAR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
  212.  
  213.     for(n=namelist;n;n=n->next) {
  214.         n->found=0;
  215.     }
  216.     if(gnu_dumpfile)
  217.         write_dir_file(gnu_dumpfile);
  218. }
  219.  
  220. int
  221. name_cmp(n1,n2)
  222. struct name *n1,*n2;
  223. {
  224.     if(n1->found) {
  225.         if(n2->found)
  226.             return strcmp(n1->name,n2->name);
  227.         else
  228.             return -1;
  229.     } else if(n2->found)
  230.         return 1;
  231.     else
  232.         return strcmp(n1->name,n2->name);
  233. }
  234.  
  235. int
  236. dirent_cmp(p1,p2)
  237. char **p1,**p2;
  238. {
  239.     char *frst,*scnd;
  240.  
  241.     frst= (*p1)+1;
  242.     scnd= (*p2)+1;
  243.  
  244.     return strcmp(frst,scnd);
  245. }
  246.  
  247. char *
  248. get_dir_contents(p,device)
  249. char *p;
  250. int device;
  251. {
  252.     DIR *dirp;
  253.     register struct direct *d;
  254.     char *new_buf;
  255.     char *namebuf = malloc(NAMSIZ+2);
  256.     int len;
  257.     VOIDSTAR the_buffer;
  258.     char *buf;
  259.     int n_strs;
  260.     int n_size;
  261.     char *p_buf;
  262.     char **vec,**p_vec;
  263.     int all_children = 0;
  264.  
  265.     extern int errno;
  266.  
  267.     errno=0;
  268.     dirp=opendir(p);
  269.     if(!dirp) {
  270.         if(errno)
  271.             msg_perror("can't open directory %s",p);
  272.         else
  273.             msg("error opening directory %s",p);
  274.         new_buf="\0\0\0\0";
  275.     } else {
  276.         (void) strcpy(namebuf,p);
  277.         if(p[strlen(p)-1]!='/')
  278.             (void) strcat(namebuf,"/");
  279.         len=strlen(namebuf);
  280.  
  281.         the_buffer=init_buffer();
  282.         while(d=readdir(dirp)) {
  283.             struct stat hs;
  284.  
  285.             /* Skip . and .. */
  286.             if(is_dot_or_dotdot(d->d_name))
  287.                 continue;
  288.             if(DP_NAMELEN(d) + len >=NAMSIZ) {
  289.                 msg("%s%s name too long: skipped",namebuf,d->d_name);
  290.                 continue;
  291.             }
  292.             (void) strcpy(namebuf+len,d->d_name);
  293.             if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs)) {
  294.                 msg_perror("can't stat %s",namebuf);
  295.                 continue;
  296.             }
  297.             if(   (f_local_filesys && device!=hs.st_dev)
  298.                || (f_exclude && check_exclude(namebuf)))
  299.                 add_buffer(the_buffer,"N",1);
  300.             else if((hs.st_mode&S_IFMT)==S_IFDIR) {
  301.                 struct dirname *dp;
  302.  
  303.                 if(dp=get_dir(namebuf)) {
  304.                     if(   dp->dev!=hs.st_dev
  305.                        || dp->ino!=hs.st_ino) {
  306.                         if(f_verbose)
  307.                             msg("directory %s has been renamed.",namebuf);
  308.                         all_children++;
  309.                         dp->dev=hs.st_dev;
  310.                         dp->ino=hs.st_ino;
  311.                     }
  312.                     dp->dir_text="";
  313.                 } else {
  314.                     if(f_verbose)
  315.                         msg("Directory %s is new",namebuf);
  316.                     add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  317.                     all_children++;
  318.                 }
  319.  
  320.                 add_buffer(the_buffer,"D",1);
  321.             } else if(   !all_children
  322.                 && f_new_files
  323.                 && new_time>hs.st_mtime
  324.                 && (   f_new_files>1
  325.                     || new_time>hs.st_ctime))
  326.                 add_buffer(the_buffer,"N",1);
  327.             else
  328.                 add_buffer(the_buffer,"Y",1);
  329.             add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  330.         }
  331.         add_buffer(the_buffer,"\000\000",2);
  332.         closedir(dirp);
  333.  
  334.         /* Well, we've read in the contents of the dir, now sort them */
  335.         buf=get_buffer(the_buffer);
  336.         if(buf[0]=='\0') {
  337.             flush_buffer(the_buffer);
  338.             new_buf="\0\0\0\0";
  339.         } else {
  340.             n_strs=0;
  341.             for(p_buf=buf;*p_buf;) {
  342.                 int tmp;
  343.  
  344.                 tmp=strlen(p_buf)+1;
  345.                 n_strs++;
  346.                 p_buf+=tmp;
  347.             }
  348.             vec=(char **)malloc(sizeof(char *)*(n_strs+1));
  349.             for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1)
  350.                 *p_vec++= p_buf;
  351.             *p_vec= 0;
  352.             qsort((VOIDSTAR)vec,n_strs,sizeof(char *),dirent_cmp);
  353.             new_buf=(char *)malloc(p_buf-buf+2);
  354.             for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) {
  355.                 char *p_tmp;
  356.  
  357.                 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
  358.                     ;
  359.             }
  360.             *p_buf++='\0';
  361.             free(vec);
  362.             flush_buffer(the_buffer);
  363.         }
  364.     }
  365.     free(namebuf);
  366.     return new_buf;
  367. }
  368.  
  369. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  370.    files is a directory, recurse on the subdirectory. . . */
  371. static void
  372. add_dir_name(p,device)
  373. char *p;
  374. int device;
  375. {
  376.     char *new_buf;
  377.     char *p_buf;
  378.  
  379.     char *namebuf = malloc(NAMSIZ+2);
  380.     register int len;
  381.  
  382.     VOIDSTAR the_buffer;
  383.  
  384.     char *buf;
  385.     char **vec,**p_vec;
  386.     int n_strs,n_size;
  387.  
  388.     struct name *n;
  389.  
  390.     /* int dirent_cmp(); REMOVED AMIGA */
  391.  
  392.     new_buf=get_dir_contents(p,device);
  393.  
  394. /*    add_dir_to_name(p,new_buf);
  395. add_dir_to_name(name,dirc)
  396. char *name;
  397. char *dirc;
  398. { */
  399.  
  400.     for(n=namelist;n;n=n->next) {
  401.         if(!strcmp(n->name,p)) {
  402.             n->dir_contents = new_buf;
  403.             break;
  404.         }
  405.     }
  406. /* } */
  407.  
  408.  
  409.     (void)strcpy(namebuf,p);
  410.     len=strlen(namebuf);
  411.     if(namebuf[len-1]!='/') {
  412.         namebuf[len++]='/';
  413.         namebuf[len]='\0';
  414.     }
  415.     for(p_buf=new_buf;*p_buf;p_buf+=strlen(p_buf)+1) {
  416.         if(*p_buf=='D') {
  417.             (void)strcpy(namebuf+len,p_buf+1);
  418.             addname(namebuf);
  419.             add_dir_name(namebuf,device);
  420.         }
  421.     }
  422.     free(namebuf);
  423. }
  424.  
  425. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  426. is_dot_or_dotdot(p)
  427. char *p;
  428. {
  429.     return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
  430. }
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437. gnu_restore(skipcrud)
  438. int skipcrud;
  439. {
  440.     char *current_dir;
  441. /*    int current_dir_length; */
  442.  
  443.     char *archive_dir;
  444. /*    int archive_dir_length; */
  445.     VOIDSTAR the_buffer;
  446.     char    *p;
  447.     DIR    *dirp;
  448.     struct direct *d;
  449.     char *cur,*arc;
  450.     extern struct stat hstat;        /* Stat struct corresponding */
  451.     long size,copied;
  452.     char *from,*to;
  453.     extern union record *head;
  454.  
  455.     dirp=opendir(skipcrud+head->header.name);
  456.  
  457.     if(!dirp) {
  458.             /* The directory doesn't exist now.  It'll be created.
  459.                In any case, we don't have to delete any files out
  460.                of it */
  461.         skip_file((long)hstat.st_size);
  462.         return;
  463.     }
  464.  
  465.     the_buffer=init_buffer();
  466.     while(d=readdir(dirp)) {
  467.         if(is_dot_or_dotdot(d->d_name))
  468.             continue;
  469.  
  470.         add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  471.     }
  472.     closedir(dirp);
  473.     add_buffer(the_buffer,"",1);
  474.  
  475.     current_dir=get_buffer(the_buffer);
  476.     archive_dir=(char *)malloc(hstat.st_size);
  477.     if(archive_dir==0) {
  478.         msg("Can't allocate %d bytes for restore",hstat.st_size);
  479.         skip_file((long)hstat.st_size);
  480.         return;
  481.     }
  482.     to=archive_dir;
  483.     for(size=hstat.st_size;size>0;size-=copied) {
  484.         from=findrec()->charptr;
  485.         if(!from) {
  486.             msg("Unexpected EOF in archive\n");
  487.             break;
  488.         }
  489.         copied=endofrecs()->charptr - from;
  490.         if(copied>size)
  491.             copied=size;
  492.         bcopy((VOIDSTAR)from,(VOIDSTAR)to,(int)copied);
  493.         to+=copied;
  494.         userec((union record *)(from+copied-1));
  495.     }
  496.  
  497.     for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
  498.         for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
  499.             arc++;
  500.             if(!strcmp(arc,cur))
  501.                 break;
  502.         }
  503.         if(*arc=='\0') {
  504.             p=new_name(skipcrud+head->header.name,cur);
  505.             if(f_confirm && !confirm("delete",p)) {
  506.                 free(p);
  507.                 continue;
  508.             }
  509.             if(f_verbose)
  510.                 fprintf(msg_file,"%s: deleting %s\n",tar,p);
  511.             if(recursively_delete(p)) {
  512.                 msg("%s: Error while deleting %s\n",tar,p);
  513.             }
  514.             free(p);
  515.         }
  516.  
  517.     }
  518.     flush_buffer(the_buffer);
  519.     free(archive_dir);
  520. }
  521.  
  522. recursively_delete(path)
  523. char *path;
  524. {
  525.     struct stat sbuf;
  526.     DIR *dirp;
  527.     struct direct *dp;
  528.     char *path_buf;
  529.     /* int path_len; */
  530.  
  531.  
  532.     if(lstat(path,&sbuf)<0)
  533.         return 1;
  534.     if((sbuf.st_mode &S_IFMT)==S_IFDIR) {
  535.  
  536.         /* path_len=strlen(path); */
  537.         dirp=opendir(path);
  538.         if(dirp==0)
  539.             return 1;
  540.         while(dp=readdir(dirp)) {
  541.             if(is_dot_or_dotdot(dp->d_name))
  542.                 continue;
  543.             path_buf=new_name(path,dp->d_name);
  544.             if(recursively_delete(path_buf)) {
  545.                 free(path_buf);
  546.                 closedir(dirp);
  547.                 return 1;
  548.             }
  549.             free(path_buf);
  550.         }
  551.         closedir(dirp);
  552.  
  553.         if(rmdir(path)<0)
  554.             return 1;
  555.         return 0;
  556.     }
  557.     if(unlink(path)<0)
  558.         return 1;
  559.     return 0;
  560. }
  561.  
  562.